import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;

/**
 * La seguente classe si occupa di gestire una singola connessione con un client
 * 
 */
public class DictionaryConnectionHandler implements Runnable {

	private Socket userSocket;
	private ObjectInputStream inputStream;
	private ObjectOutputStream outputStream;
	private ItEnDictionary dictionary;
	private boolean closedConnection;

	public DictionaryConnectionHandler(Socket userSocket,
			ItEnDictionary dictionary) {
		super();
		this.userSocket = userSocket;
		this.dictionary = dictionary;
		this.closedConnection = false;
		try {
			inputStream = new ObjectInputStream(new BufferedInputStream(
					userSocket.getInputStream()));
			outputStream = new ObjectOutputStream(new BufferedOutputStream(
					userSocket.getOutputStream()));
			outputStream.flush();
		} catch (IOException e) {
			try {
				userSocket.close();
			} catch (IOException e1) {
			}
		}
	}

	/**
	 * Gestisce l'attesa di nuovi messaggi dal client e l'invio dell'apposita
	 * risposta
	 */
	@Override
	public void run() {
		while (!closedConnection) {
			try {
				// Leggo la richiesta
				Message receivedMessage = (Message) inputStream.readObject();
				// Elaboro la risposta
				Message responseMessage = processReqeust(receivedMessage);
				// Se non è stata chiusa la connessione in seguito alla
				// richiesta invio la risposta
				if (!closedConnection && responseMessage!=null) {
					outputStream.writeObject(responseMessage);
					outputStream.flush();
				}
			} catch (IOException e) {
				try {
					inputStream.close();
					outputStream.close();
					userSocket.close();
					closedConnection = true;
				} catch (IOException e1) {
				}

			} catch (ClassNotFoundException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}

	}

	/**
	 * Consente di elaborare le richieste del client decifrando il messaggio di
	 * richiesta e producendo un messaggio di risposta.
	 * 
	 * @param requestMessage
	 *            Messaggio di richiesta del client
	 * @return Messaggio di risposta da inviare al Client
	 * @throws IOException
	 */
	public Message processReqeust(Message requestMessage) throws IOException {
		Message responseMessage = null;

		switch (requestMessage.getOperation()) {
		case INSERT:
			boolean result = dictionary.addWord(requestMessage.getItaWord(),
					requestMessage.getEngWord());
			if (result)
				responseMessage = MessageFactory.GenerateInsertResponse(
						requestMessage.getItaWord(),
						requestMessage.getEngWord(), false);
			else

				responseMessage = MessageFactory.GenerateInsertResponse(
						requestMessage.getItaWord(),
						dictionary.getWord(requestMessage.getItaWord()), true);

			break;
		case PING:
			responseMessage = MessageFactory.GeneratePingResponse();
			break;
		case TRANSLATE:
			String translation = dictionary
					.getWord(requestMessage.getItaWord());
			boolean hasError = true;
			if (translation != null) {
				hasError = false;
			}

			responseMessage = MessageFactory.GenerateTranslateResponse(
					requestMessage.getItaWord(), translation, hasError);
			break;
		case CLOSESOCKET:
			closedConnection = true;
			inputStream.close();
			outputStream.close();
			userSocket.close();
			break;
		default:
			break;

		}

		return responseMessage;
	}
}
